package com.swu.pad.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.aspectj.weaver.patterns.ThisOrTargetAnnotationPointcut;
import org.netlib.blas.Lsame;
import org.netlib.util.doubleW;

import com.huaban.analysis.jieba.JiebaSegmenter;

import libsvm.svm;
import weka.classifiers.Classifier;
import weka.classifiers.trees.RandomForest;
import weka.core.Attribute;
import weka.core.DenseInstance;
import weka.core.Instance;
import weka.core.Instances;

public class DocToSentencesClassUtil {
	
	//jieba分词工具
	public static JiebaSegmenter jbSeg = new JiebaSegmenter();
	//当前类对象
	public static DocToSentencesClassUtil dtscu=new DocToSentencesClassUtil();
	//保留两位小数
	public static  DecimalFormat df = new DecimalFormat("#.00");

	/*
	 * 传入句子数组分词  输出 句子+分词 数组
	 */
	public static Map<String,Object> docSentenceClass(String docText)throws Exception {
		String[] docSentences=docTextToSentec(docText);//1分句
		List<Map<String,Object>> sentenceCutwords=cutSentence(docSentences);//2分词 去停止词
		List<Map<String,Object>> sentenceFesCount=countFeNum(sentenceCutwords);//3 统计 所有 词语 特征相对频率
		List<Map<String,Object>> sentenceInstance=makeInstanceList(sentenceFesCount);//4根据所有句子频率 ，lc特征构建待遇测数据集
		Map<String,Object> sentencesClass=classifyInstances(sentenceInstance);//5预测句子类别
		return sentencesClass;
	}
	
	
	
	/*
	 * 传入文章text 对文章进行分句
	 */
	public static String[] docTextToSentec(String docText)throws Exception {
		    //1  去空格 回车 换行 制表符
		    Pattern p = Pattern.compile("\\s*|\t|\r|\n");
		    Matcher m = p.matcher(docText);
		    docText = m.replaceAll("");
		    //2分句符号 切分	    
		    String regEx="[。！？. ? ! ; ；]";
			p =Pattern.compile(regEx);
			m = p.matcher(docText);

		    String[] substrs =p.split(docText);
            return substrs;
	}
	
     
	/*
	 * 传入句子数组分词  输出 句子+分词 数组
	 */
	public static List<Map<String,Object>> cutSentence(String[] textSentens)throws Exception {
		List<Map<String,Object>> results=new ArrayList<Map<String,Object>>();
		//1获取停止词列表
		String stpwordFile=readToString(dtscu.getClass().getResource("/sentenceClass/stpwords.txt").getPath());
		//2 提取所有停止词
	    String[] stpwords=stpwordFile.split("\r\n");
	    List<String> stpwds=new ArrayList<String>();
		for (int i = 0; i < stpwords.length; i++) {
			stpwds.add(stpwords[i]);//构建停止词list
		}
		//3分词		
		for (int i = 0; i < textSentens.length; i++) {
			//System.out.println(textSentens[i]);
			Map<String,Object> tempMap=new HashMap<String, Object>();
			tempMap.put("sentence",textSentens[i]);
			List<String> cutSentence = jbSeg.sentenceProcess(textSentens[i]);
			cutSentence.removeAll(stpwds);
			tempMap.put("nostpSentence", cutSentence);//去停止词
			results.add(tempMap);
		}
		return results;
	}
	
	/*
	 * 传入句子数组统计  输出 句子，分词 特征统计 
	 */
	public static List<Map<String,Object>> countFeNum(List<Map<String,Object>> cutSentenses)throws Exception {
		List<Map<String,Object>> ctResList=new ArrayList<Map<String,Object>>();
		//1取静态文件
		String lc=readToString(dtscu.getClass().getResource("/sentenceClass/lcindex.txt").getPath());
		String[] lcs=lc.split("\r\n");//lc 索引   数组 是有序的，按照读取顺序排列
		String lcdict=readToString(dtscu.getClass().getResource("/sentenceClass/sc_liwc.dic").getPath());
		String[] lcds=lcdict.split("\r\n");//lc 字典里的所有行
		//存储所有 词   以及 对应序号
		List<String[]> alLcWords=new ArrayList<String[]>();//存储所有lc 词 与 对应类别
		for (int i = 0; i < lcds.length; i++) {
			String[] lsc=lcds[i].split(" ");
			alLcWords.add(lsc);//将liwc字典的每一行 都加入到  一个list 里  。
		}
		
		
		
		//2遍历句子，统计特征数量
		for (int i = 0; i < cutSentenses.size(); i++) {//遍历句子列表
			Map<String,Object> 	tempMap=cutSentenses.get(i);//将原来的  句子 ，句子分子 赋值给新map 后面put上一个新key保存特征数量
		    //tlcvs=0#存放总 lc 次数
			//构建   特征  字典 key字典数字  value 出现数量
			List<List<String>> lcIndexAndCount=new ArrayList<List<String>>();//存下标 和 数字
			for (int j = 0; j < lcs.length; j++) {
				String[] tempsplit=lcs[j].split(",");
				List<String> temps=new ArrayList<String>();
				temps.add(tempsplit[0]);//字典下标
				temps.add("0");
				temps.add(tempsplit[1]);//
				lcIndexAndCount.add(temps);
			}
			List<String> nosentence=(List<String>)cutSentenses.get(i).get("nostpSentence");
			for (int j = 0; j < nosentence.size(); j++) {  //遍历每个句子的 每个词
				 for (int k = 0; k < alLcWords.size();k++) {
					if (nosentence.get(j).equals(alLcWords.get(k)[0])) {// 一句话中的词 == 字典里某个词时
						for (int m = 0; m < alLcWords.get(k).length; m++) {//遍历当前 字典 行； 词语 数字 数字。。
							if(isInteger(alLcWords.get(k)[m])) {//是数字
								for (int n = 0; n < lcIndexAndCount.size(); n++) {
									if(lcIndexAndCount.get(n).get(0).equals(alLcWords.get(k)[m])) {
										List<String> tempLcIndex=new ArrayList<String>();
									    tempLcIndex.add(lcIndexAndCount.get(n).get(0));//下标
									    tempLcIndex.add(lcIndexAndCount.get(n).get(1));//次数
									    tempLcIndex.add(lcIndexAndCount.get(n).get(2));
										tempLcIndex.set(1,Integer.toString(Integer.parseInt(lcIndexAndCount.get(n).get(1))+1));
										lcIndexAndCount.set(n, tempLcIndex);
									}
								}
							}
						}
					}
				}
			}
			//3 计算 每个句子 每个lc 特征比值
			int tlcv=0;//存放每个 句子的  lc 总数
			for (int lii = 0; lii < lcIndexAndCount.size(); lii++) {
				tlcv=tlcv+Integer.parseInt(lcIndexAndCount.get(lii).get(1));
			}
			for (int lii = 0; lii < lcIndexAndCount.size(); lii++) {
				if ((!lcIndexAndCount.get(lii).get(1).equals("0.0"))&&tlcv!=0.0) {
					double feCount=Double.valueOf(Integer.parseInt(lcIndexAndCount.get(lii).get(1)));		
					lcIndexAndCount.get(lii).set(1,String.format("%.2f",feCount/tlcv));//设置比值
					lcIndexAndCount.get(lii).set(1,Double.toString(Double.valueOf(lcIndexAndCount.get(lii).get(1))*100));
					lcIndexAndCount.get(lii).set(1,lcIndexAndCount.get(lii).get(1).split("\\.")[0]);
				}
				
			}
			
			tempMap.put("lcFeRatio",lcIndexAndCount);
			ctResList.add(tempMap);
		}
		
		return ctResList;
	}
	
	
	
	/*
	 * 传入句子特征比值数组统计  输出 instances  
	 */
	public static List<Map<String,Object>> makeInstanceList(List<Map<String,Object>> feNums)throws Exception {
		List<Map<String,Object>> ctResList=new ArrayList<Map<String,Object>>();
		//1 加载静态资源
		/*
		 * String classContent=readToString(dtscu.getClass().getResource(
		 * "/sentenceClass/classIndex.txt").getPath()); String[]
		 * classCts=classContent.split("\r\n");
		 */
		List<List<String>> classIndexAndValues=getClassInfos();//存 句子类别 下标 和 内容 
		/*
		 * for (int i = 0; i < classCts.length; i++) { String[]
		 * tempsplit=classCts[i].split(","); List<String> temps=new ArrayList<String>();
		 * temps.add(tempsplit[0]);//字典下标 temps.add(tempsplit[1]);
		 * temps.add(tempsplit[2]);// classIndexAndValues.add(temps); }
		 */
		// ----- 构造  特征表 ，加载读取  lc-fe
		String lcFeContent=readToString(dtscu.getClass().getResource("/sentenceClass/lcindex.txt").getPath());
		String[] lcFeCts=lcFeContent.split("\r\n");
		List<List<String>> lcValues=new ArrayList<List<String>>();//存 lc 类别 ，相当于  instance 的 表头 ，也是所有的 
		for (int i = 0; i < lcFeCts.length; i++) {   
			String[] tempsplit=lcFeCts[i].split(",");
			List<String> temps=new ArrayList<String>();
			temps.add(tempsplit[0]);//lcfe下标
			temps.add(tempsplit[1]);//lcfe名称
			lcValues.add(temps);
		}
	    
		//2构建  instances 。相当于存放整篇文章的 数据集，每一行是一个句子 对应的特征表数据
		ArrayList<Attribute> attributes=new ArrayList<Attribute>();//存放所有属性名称  ，第一行数据  ，funct，neg，。。。money，relativ
		List<String> classValues= new ArrayList<String>(); 
		for (int i = 0; i < classIndexAndValues.size(); i++) {//构建 class类别  nominal  ：离散型数据 ，other ，belief。。。
			classValues.add(classIndexAndValues.get(i).get(1));
		}
		Attribute classAttribute = new Attribute("class", classValues); 
		attributes.add(classAttribute);//将class 属性加入到属性列
		for (int i = 0; i < lcValues.size(); i++) {
			Attribute tempAttribute = new Attribute(lcValues.get(i).get(1));//按顺序创建 属性
			attributes.add(tempAttribute);
		}
		//2 遍历 所有句子  构建  instance
		Instances unlabelSentence=new Instances("sentenceFes",attributes,0);
		unlabelSentence.setClassIndex(0);//设置 0 列是class列
		for (int i = 0; i < feNums.size(); i++) {
			//map key  sentence   nostpSentence    lcFeRatio
			Map<String,Object> tempMap=feNums.get(i);//取出原始 数据 map  ，最后add instance实例
			List<List<String>> lcRatiols=(List<List<String>>) tempMap.get("lcFeRatio");
			Instance instance=new DenseInstance(unlabelSentence.numAttributes());//创建实例，属性数量等于 unlabel句子属性数量
			for (int j = 0; j < lcRatiols.size(); j++) {
				for (int k = 0; k < attributes.size(); k++) {
					if (attributes.get(k).name().equals(lcRatiols.get(j).get(2))) {//相等了
						//如果属性名称对应了，那么就将 对应的 属性   值  赋值
						instance.setValue(attributes.get(k),Double.valueOf(lcRatiols.get(j).get(1)));
					}
				}
			}// 一个句子的   所有属性 被赋值完毕  将其加入到 instances  实例数据 集合 中
			instance.setDataset(unlabelSentence);//所有的instance创建完成后都要设置 归属的 dataset，也就是instances数据集，好对应属性。class的类别 
			tempMap.put("instance",instance);
			unlabelSentence.add(instance);
			ctResList.add(tempMap);
            //构造数据集  end
		}
		return ctResList;
	}
	
	/*
	 * 传入句子 instance ， 对句子进行分类 
	 */
	public static Map<String,Object> classifyInstances(List<Map<String,Object>> unlabelInstances)throws Exception {
		//1 获取分类器实例
		 Map<String,Object> results=new HashMap<String, Object>();
		 List<Map<String,Object>> ctResList=new ArrayList<Map<String,Object>>();
		 Classifier cfer= (Classifier) weka.core.SerializationHelper.read("C:\\RandomForest.model"); 
		//2获取 label对应的 index
		 String classContent=readToString(dtscu.getClass().getResource("/sentenceClass/classIndex.txt").getPath());
		 String[] classCts=classContent.split("\r\n");
		 List<List<String>> classIndexAndValues=getClassInfos();//存 句子   类别 下标 和 名称 
		/*
		 * for (int i = 0; i < classCts.length; i++) { String[]
		 * tempsplit=classCts[i].split(","); List<String> temps=new ArrayList<String>();
		 * if (i==0) { temps.add(tempsplit[0].substring(1));//class 的 index double值
		 * ,!utf-8 第一个字符为 空字符 需要 分割一下，取第二个 有数值的子字符串 }else {
		 * temps.add(tempsplit[0]);//不是第一行，正常添加 }
		 * 
		 * temps.add(tempsplit[1]);//class 的 英文名称 temps.add(tempsplit[2]);//class 的中文名称
		 * temps.add(tempsplit[3]); classIndexAndValues.add(temps); }
		 */
		 results.put("classInfo",classIndexAndValues);
		 //2遍历句子 分类
		 for (int i = 0; i < unlabelInstances.size(); i++) {
		 //map key  sentence  instance:对此分类    nostpSentence    lcFeRatio
		 Map<String,Object> tempMap=unlabelInstances.get(i);//取出原始 数据 map  ，最后add instance 的类别
		 Instance instance=(Instance) tempMap.get("instance");
		 double classValue=cfer.classifyInstance(instance);
		 String classIndex=Double.toString(classValue).split("\\.")[0];
		 String sentenceClass="";//存放句子类别  中文 
		 for (int j = 0; j <classIndexAndValues.size(); j++) {
			if (classIndex.equals(classIndexAndValues.get(j).get(0))) {
				sentenceClass=classIndexAndValues.get(j).get(2);//中文 类别名称
			}
		 }
		// System.out.println(sentenceClass+"--->"+tempMap.get("sentence"));
		 tempMap.put("class",sentenceClass);
		 ctResList.add(tempMap);
		 }
		 results.put("sentenceInfo", ctResList);
		 return results;
	}
	
	public  static  List<List<String>> getClassInfos(){
		//2获取 label对应的 index
		 String classContent=readToString(dtscu.getClass().getResource("/sentenceClass/classIndex.txt").getPath());
		 String[] classCts=classContent.split("\r\n");
		 List<List<String>> classIndexAndValues=new ArrayList<List<String>>();//存 句子   类别 下标 和 名称 
		 for (int i = 0; i < classCts.length; i++) {   
				String[] tempsplit=classCts[i].split(",");
				List<String> temps=new ArrayList<String>();
				if (i==0) {
					temps.add(tempsplit[0].substring(1));//class 的 index double值  ,!utf-8 第一个字符为  空字符 需要 分割一下，取第二个 有数值的子字符串	
				}else {
					temps.add(tempsplit[0]);//不是第一行，正常添加
				}
				
				temps.add(tempsplit[1]);//class 的 英文名称
				temps.add(tempsplit[2]);//class 的中文名称
				temps.add(tempsplit[3]);//class 解释
				temps.add(tempsplit[4]);//class 的图标
				temps.add(tempsplit[5]);//class 的顺序
				temps.add(tempsplit[6]);//class 图标的颜色
				classIndexAndValues.add(temps);
		 }
		return classIndexAndValues;
		
	}
	
	
	
	public static String readToString(String fileName) {  
        String encoding = "UTF-8";  
        File file = new File(fileName);  
        Long filelength = file.length();  
        byte[] filecontent = new byte[filelength.intValue()];  
        try {  
            FileInputStream in = new FileInputStream(file);  
            in.read(filecontent);
            in.close();  
        } catch (FileNotFoundException e) {  
            e.printStackTrace();  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
        try {  
            return new String(filecontent, encoding);  
        } catch (UnsupportedEncodingException e) {  
            System.err.println("The OS does not support " + encoding);  
            e.printStackTrace();  
            return null;  
        }  
    }
	  //判断是字符串是否为数字
	 public static boolean isInteger(String str) {  
	        Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
	        return pattern.matcher(str).matches();  
	  }
	
	
}
